package task3.erode;

import java.awt.image.renderable.ParameterBlock;
import java.security.InvalidParameterException;
import javax.media.jai.JAI;
import javax.media.jai.KernelJAI;
import task3.pimpmypipe.DataTransformationFilter;
import task3.util.FilterObservable;
import task3.util.ImageTO;

public class ErodeFilter
  extends DataTransformationFilter<ImageTO>
{
  private int _kernelSize;
  private FilterObservable _observable;
  
  public ErodeFilter()
    throws InvalidParameterException
  {
    this._kernelSize = 6;
    this._observable = new FilterObservable();
  }
  
  protected void process(ImageTO entity)
  {
    KernelJAI kernel = createRoundKernel(this._kernelSize);
    
    ParameterBlock parameters = new ParameterBlock();
    parameters.addSource(entity.getEditedImage());
    parameters.add(kernel);
    
    entity.setEditedImage(JAI.create("erode", parameters));
    
    this._observable.setChanged();
    this._observable.notifyObservers(entity);
  }
  
  private KernelJAI createRoundKernel(int radius)
  {
    int diameter = 2 * radius + 1;
    float[] data = new float[diameter * diameter];
    
    int[] offset = new int[diameter];
    int i = 0;
    for (int o = 0; i < diameter; o += diameter)
    {
      offset[i] = o;i++;
    }
    int x = radius;int y = 0;
    int r2 = radius * radius;
    while (x > 0)
    {
      int ix = radius + x;
      int iy = radius + y;
      data[(ix + offset[iy])] = 1.0F;
      data[(diameter - 1 - ix + offset[iy])] = 1.0F;
      iy = diameter - 1 - iy;
      data[(ix + offset[iy])] = 1.0F;
      data[(diameter - 1 - ix + offset[iy])] = 1.0F;
      y--;
      x = (int)Math.sqrt(r2 - y * y);
    }
    data[radius] = 1.0F;
    data[(radius + offset[(2 * radius)])] = 1.0F;
    
    int k = 0;
    for (int y2 = 0; y2 < diameter; y2++)
    {
      int left = -1;int right = -1;
      for (int x2 = 0; x2 < diameter; k++)
      {
        if (data[k] > 0.0F) {
          if (left < 0) {
            left = k;
          } else {
            right = k;
          }
        }
        x2++;
      }
      while (right > left + 1) {
        data[(--right)] = 1.0F;
      }
    }
    return new KernelJAI(diameter, diameter, data);
  }
  
  public int getKernelSize()
  {
    return this._kernelSize;
  }
  
  public void setKernelSize(int kernelSize)
  {
    this._kernelSize = kernelSize;
  }
  
  public FilterObservable getObservable()
  {
    return this._observable;
  }
}
